﻿namespace Filters.Demo.DataAccess
{
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;
    using AForge.Math;

    public static class EntityTranslator
    {
        private const char PointSeparator = '|';
        private const char ElementSeparator = ';';
        private const string Specifier = "G";
        private const NumberStyles NumberStyle = NumberStyles.Float | NumberStyles.Integer | NumberStyles.Number;

        public static ImageModel ToModel(this Signatures imageData)
        {
            return new ImageModel
                       {
                           ImageID = imageData.ImageID,
                           ImageName = imageData.ImageName,
                           ImageSignature = GetSignature(imageData.ImageSignature),
                           ImageOriginal = GetImage(imageData.ImageOriginal),
                           ImageBinarized = GetImage(imageData.ImageBinarized),
                           DistanceToPivot = imageData.DistanceToPivot.HasValue ? imageData.DistanceToPivot.Value : 0,
                           PivotID = imageData.Pivot != null ? imageData.Pivot.PivotID : 0
                       };
        }

        public static PivotModel ToModel(this Pivots pivotData)
        {
            return new PivotModel
            {
                PivotID = pivotData.PivotID,
                ImageModel = pivotData.PivotSignature.ToModel()
            };
        }

        public static Signatures ToData(this ImageModel imageModel, IEnumerable<Pivots> pivots)
        {
            return new Signatures
            {
                ImageID = imageModel.ImageID,
                ImageName = imageModel.ImageName,
                ImageSignature = GetSignature(imageModel.ImageSignature),
                ImageOriginal = GetImage(imageModel.ImageOriginal),
                ImageBinarized = GetImage(imageModel.ImageBinarized),
                DistanceToPivot = imageModel.DistanceToPivot,
                Pivot = pivots.FirstOrDefault(p => p.PivotID == imageModel.PivotID)
            };
        }

        public static Pivots ToData(this PivotModel pivotModel, IEnumerable<Signatures> signatures)
        {
            return new Pivots
            {
                PivotID = pivotModel.PivotID,
                PivotSignature = signatures.FirstOrDefault(sg => sg.ImageID == pivotModel.ImageModel.ImageID)
            };
        }

        private static Complex[] GetSignature(string signature)
        {
            var signatureArray = new List<Complex>();

            foreach (var point in signature.Split(PointSeparator))
            {
                if (point.Contains(ElementSeparator))
                {
                    var elements = point.Split(ElementSeparator);

                    signatureArray.Add(new Complex(double.Parse(elements[0], NumberStyle, CultureInfo.InvariantCulture), double.Parse(elements[1], NumberStyle, CultureInfo.InvariantCulture)));
                }
            }

            return signatureArray.ToArray();
        }

        private static string GetSignature(IEnumerable<Complex> signature)
        {
            var builder = new StringBuilder();

            foreach (var point in signature)
            {
                builder.Append(string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", point.Re.ToString(Specifier, CultureInfo.InvariantCulture), ElementSeparator, point.Im.ToString(Specifier, CultureInfo.InvariantCulture), PointSeparator));
            }

            return builder.ToString();
        }

        private static Image GetImage(byte[] image)
        {
            return Image.FromStream(new MemoryStream(image));
        }

        private static byte[] GetImage(Image image)
        {
            var stream = new MemoryStream();
            image.Save(stream, ImageFormat.Jpeg);

            return stream.ToArray();
        }
    }
}
